隆Hola 馃憢! Espera mientras comienza la sesi贸n.

Antes que todo, 驴c贸mo est谩n?

Visualizaci贸n de Informaci贸n

IIC2026 2021-2

Utilidades en D3.js II

Visualizaci贸n de Informaci贸n

IIC2026 2021-2

Contenidos


1. Eventos en D3.js

2. Transiciones de D3.js

3. Join de datos personalizado

隆M谩s detalles para nuestro programa!


Comenzamos con una visualizaci贸n est谩tica.


Terminamos con una visualuzaci贸n din谩mica e interactiva.

Eventos



const width = 600;
const height = 400;
const margin = {
  top: 30,
  bottom: 30,
  right: 30,
  left: 30,
};

const svg = d3
  .select("body")
  .append("svg")
  .attr("width", width)
  .attr("height", height);

const boton = d3.select("body").append("button").text("Agregar elemento");

const parrafo = d3.select("body").append("p");

const contenedorEjeY = svg
  .append("g")
  .attr("transform", `translate(${margin.left}, ${margin.top})`);

const contenedorEjeX = svg
  .append("g")
  .attr("transform", `translate(${margin.left}, ${height - margin.bottom})`);

const contenedorBarras = svg
  .append("g")
  .attr("transform", `translate(${margin.left} ${margin.top})`);

function joinDeDatos(datos) {
  const maximaFrecuencia = d3.max(datos, (d) => d.frecuencia);

  const escalaAltura = d3
    .scaleLinear()
    .domain([0, maximaFrecuencia])
    .range([0, height - margin.top - margin.bottom]);

  const escalaY = d3
    .scaleLinear()
    .domain([0, maximaFrecuencia])
    .range([height - margin.top - margin.bottom, 0]);

  const ejeY = d3.axisLeft(escalaY);

  contenedorEjeY
    .transition()
    .duration(1000)
    .call(ejeY)
    .selection()
    .selectAll("line")
    .attr("x1", width - margin.right - margin.left)
    .attr("stroke-dasharray", "5")
    .attr("opacity", 0.5);

  const escalaX = d3
    .scaleBand()
    .domain(datos.map((d) => d.categoria))
    .rangeRound([0, width - margin.right - margin.left])
    .padding(0.5);

  const ejeX = d3.axisBottom(escalaX);

  contenedorEjeX
    .transition()
    .duration(1000)
    .call(ejeX)
    .selection()
    .selectAll("text")
    .attr("font-size", 20);

  contenedorBarras
    .selectAll("rect")
    .data(datos, (d) => d.categoria)
    .join(
      (enter) =>
        enter
          .append("rect")
          .attr("fill", "magenta")
          .attr("y", height - margin.top - margin.bottom)
          .attr("x", (d) => escalaX(d.categoria))
          .attr("width", escalaX.bandwidth())
          .attr("height", 0)
          .transition()
          .duration(1000)
          .attr("height", (d) => escalaAltura(d.frecuencia))
          .attr("y", (d) => escalaY(d.frecuencia))
          .selection(),
      (update) =>
        update
          .transition()
          .duration(1000)
          .attr("height", (d) => escalaAltura(d.frecuencia))
          .attr("y", (d) => escalaY(d.frecuencia))
          .attr("x", (d) => escalaX(d.categoria))
          .attr("width", escalaX.bandwidth())
          .selection(),
      (exit) =>
        exit
          .transition()
          .duration(500)
          .attr("y", height - margin.top - margin.bottom)
          .attr("height", 0)
          .remove()
    )
    .on("mouseenter", (_, d) => {
      parrafo.text(`Categor铆a: ${d.categoria}, Frecuencia: ${d.frecuencia}`);
    })
    .on("mouseleave", () => {
      parrafo.text("");
    })
    .on("click", (_, d) => {
      datos.splice(datos.indexOf(d), 1);
      joinDeDatos(datos);
    });
}

const datoNuevoRandom = (datos) => ({
  categoria: String.fromCharCode(
    datos[datos.length - 1].categoria.charCodeAt(0) + 1
  ),
  frecuencia: Math.floor(Math.random() * 800),
});

let datos;

d3.json("datos.json")
  .then((datosCargados) => {
    console.log(datosCargados);
    datos = datosCargados;
    joinDeDatos(datos);
    boton.on("click", () => {
      datos.push(datoNuevoRandom(datos));
      joinDeDatos(datos);
    });
  })
  .catch((error) => console.log(error));
          

Eventos


隆Hay muchos tipos de eventos!


  • click
  • dbclick
  • change
  • dragstart
  • dragover
  • ...

Lista de eventos: MDN

Transiciones



const width = 600;
const height = 400;
const margin = {
  top: 30,
  bottom: 30,
  right: 30,
  left: 30,
};

const svg = d3
  .select("body")
  .append("svg")
  .attr("width", width)
  .attr("height", height);

const boton = d3.select("body").append("button").text("Agregar elemento");

const parrafo = d3.select("body").append("p");

const contenedorEjeY = svg
  .append("g")
  .attr("transform", `translate(${margin.left}, ${margin.top})`);

const contenedorEjeX = svg
  .append("g")
  .attr("transform", `translate(${margin.left}, ${height - margin.bottom})`);

const contenedorBarras = svg
  .append("g")
  .attr("transform", `translate(${margin.left} ${margin.top})`);

function joinDeDatos(datos) {
  const maximaFrecuencia = d3.max(datos, (d) => d.frecuencia);

  const escalaAltura = d3
    .scaleLinear()
    .domain([0, maximaFrecuencia])
    .range([0, height - margin.top - margin.bottom]);

  const escalaY = d3
    .scaleLinear()
    .domain([0, maximaFrecuencia])
    .range([height - margin.top - margin.bottom, 0]);

  const ejeY = d3.axisLeft(escalaY);

  contenedorEjeY
    .transition()
    .duration(1000)
    .call(ejeY)
    .selection()
    .selectAll("line")
    .attr("x1", width - margin.right - margin.left)
    .attr("stroke-dasharray", "5")
    .attr("opacity", 0.5);

  const escalaX = d3
    .scaleBand()
    .domain(datos.map((d) => d.categoria))
    .rangeRound([0, width - margin.right - margin.left])
    .padding(0.5);

  const ejeX = d3.axisBottom(escalaX);

  contenedorEjeX
    .transition()
    .duration(1000)
    .call(ejeX)
    .selection()
    .selectAll("text")
    .attr("font-size", 20);

  contenedorBarras
    .selectAll("rect")
    .data(datos, (d) => d.categoria)
    .join(
      (enter) =>
        enter
          .append("rect")
          .attr("fill", "magenta")
          .attr("y", height - margin.top - margin.bottom)
          .attr("x", (d) => escalaX(d.categoria))
          .attr("width", escalaX.bandwidth())
          .attr("height", 0)
          .transition()
          .duration(1000)
          .attr("height", (d) => escalaAltura(d.frecuencia))
          .attr("y", (d) => escalaY(d.frecuencia))
          .selection(),
      (update) =>
        update
          .transition()
          .duration(1000)
          .attr("height", (d) => escalaAltura(d.frecuencia))
          .attr("y", (d) => escalaY(d.frecuencia))
          .attr("x", (d) => escalaX(d.categoria))
          .attr("width", escalaX.bandwidth())
          .selection(),
      (exit) =>
        exit
          .transition()
          .duration(500)
          .attr("y", height - margin.top - margin.bottom)
          .attr("height", 0)
          .remove()
    )
    .on("mouseenter", (_, d) => {
      parrafo.text(`Categor铆a: ${d.categoria}, Frecuencia: ${d.frecuencia}`);
    })
    .on("mouseleave", () => {
      parrafo.text("");
    })
    .on("click", (_, d) => {
      datos.splice(datos.indexOf(d), 1);
      joinDeDatos(datos);
    });
}

const datoNuevoRandom = (datos) => ({
  categoria: String.fromCharCode(
    datos[datos.length - 1].categoria.charCodeAt(0) + 1
  ),
  frecuencia: Math.floor(Math.random() * 800),
});

let datos;

d3.json("datos.json")
  .then((datosCargados) => {
    console.log(datosCargados);
    datos = datosCargados;
    joinDeDatos(datos);
    boton.on("click", () => {
      datos.push(datoNuevoRandom(datos));
      joinDeDatos(datos);
    });
  })
  .catch((error) => console.log(error));
          

Transiciones


Detalles de transiciones en subm贸dulo d3-transition.


  • Tienen un m茅todo delay para fijar un atraso.
  • Tienen un m茅todo ease para alterar como es el cambio en el tiempo.

Join de datos perzonalizado

selecci贸n grupo rect rect rect rect rect datos arreglo 4 18 23 42

              selection.data(data);
            
selecci贸n grupo rect 0 rect 1 rect 2 rect 3 rect 4 datos arreglo 4 0 18 1 23 2 42 3
selecci贸n grupo rect rect rect rect rect datos arreglo 4 18 23 42

              selection.data(data, (d) => d.llave);
            
selecci贸n grupo rect A rect B rect C rect D rect E datos arreglo 4 A 18 C 23 D 42 E

隆Practico entre todes!

隆Visualizaci贸n del d铆a!

P谩gina intectiva de informaci贸n sobre armas nucleares.

Propuesta por estudiante "Java B".

(Fuente: Outrider - Nuclear Weapons Interactive)

Pr贸ximos eventos:


Pr贸xima senaba revisaremos el material de Visualizaci贸n de datos tabulares y Layouts tabulares en D3.js.

Domingo 26 de septiembre (20:00:00) termina plazo de Hito 1.

Utilidades en D3.js II

Visualizaci贸n de Informaci贸n

IIC2026 2021-2


隆Deja tus preguntas en los comentarios!